package com.example.springbootdemo;

import com.example.springbootdemo.bean.Bean4;
import com.example.springbootdemo.bean.child.Bean04;
import com.example.springbootdemo.bean.child.Bean05;
import com.example.springbootdemo.event.UserRegisteredEvent;
import com.example.springbootdemo.service.AopService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.Resource;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@Slf4j
@SpringBootApplication
public class SpringbootDemoApplication {

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(SpringbootDemoApplication.class, args);
    AopService service = context.getBean("aopService", AopService.class);
    System.out.println(service.getClass());
    service.foo();
    context.close();
  }

  @Bean(initMethod = "init3")
  public Bean04 bean04(){
    return new Bean04();
  }

  @Bean(destroyMethod = "destroy3")
  public Bean05 bean05(){
    return new Bean05();
  }

  public static void testMyBeanFactory(){
    MyBeanFactory beanFactory = new MyBeanFactory();
    beanFactory.addProcessor(bean -> System.out.println("解析 @Autowired"));
    beanFactory.addProcessor(bean -> System.out.println("解析 @Resource"));
    beanFactory.getBean();
  }

  static class MyBeanFactory {
    public Object getBean() {
      Object bean = new Object();
      System.out.println("构造 " + bean);
      System.out.println("依赖注入 " + bean);
      for (BeanPostProcessor processor : processors) {
        processor.inject(bean);
      }
      System.out.println("初始化 " + bean);
      return bean;
    }

    private List<BeanPostProcessor> processors = new ArrayList<>();

    public void addProcessor(BeanPostProcessor processor){
      processors.add(processor);
    }
  }

  static interface BeanPostProcessor {
    void inject(Object bean);
  }

  public static void testPrototype(ConfigurableApplicationContext context){
    Bean4 bean4 = context.getBean("bean4", Bean4.class);
    log.info("prototype 直接加载");
    System.out.println(bean4.getBeanForPrototype().getClass());
    System.out.println(bean4.getBeanForPrototype());
    System.out.println(bean4.getBeanForPrototype());
    System.out.println(bean4.getBeanForPrototype());
    log.info("prototype 懒加载");
    System.out.println(bean4.getBeanForPrototype2().getClass());
    System.out.println(bean4.getBeanForPrototype2());
    System.out.println(bean4.getBeanForPrototype2());
    System.out.println(bean4.getBeanForPrototype2());
    log.info("prototype target_class");
    System.out.println(bean4.getBeanForPrototype3().getClass());
    System.out.println(bean4.getBeanForPrototype3());
    System.out.println(bean4.getBeanForPrototype3());
    System.out.println(bean4.getBeanForPrototype3());
    log.info("prototype objectFactory");
    System.out.println(bean4.getBeanForPrototype4().getClass());
    System.out.println(bean4.getBeanForPrototype4());
    System.out.println(bean4.getBeanForPrototype4());
    System.out.println(bean4.getBeanForPrototype4());
    log.info("prototype applicationContext 有点炸裂");
    System.out.println(bean4.getBeanForPrototype5().getClass());
    System.out.println(bean4.getBeanForPrototype5());
    System.out.println(bean4.getBeanForPrototype5());
    System.out.println(bean4.getBeanForPrototype5());
  }

  public static void testContext(ConfigurableApplicationContext context) throws Exception {
    Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
    singletonObjects.setAccessible(true);
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
    for (String key : map.keySet().stream().filter(x -> x.startsWith("User")).toList()) {
      System.out.println(key + ":" + map.get(key));
    }

    System.out.println(context.getMessage("hi", null, Locale.CHINA));
    System.out.println(context.getMessage("hi", null, Locale.CHINESE));
    System.out.println(context.getMessage("hi", null, Locale.TRADITIONAL_CHINESE));
    System.out.println(context.getMessage("hi", null, Locale.SIMPLIFIED_CHINESE));
    System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
    System.out.println(context.getMessage("hi", null, Locale.JAPANESE));

    Resource resource = context.getResource("classpath:application.properties");
    System.out.println(resource);
    Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
    for (Resource res : resources) {
      System.out.println(res);
    }

    System.out.println(context.getEnvironment().getProperty("java_home"));
    System.out.println(context.getEnvironment().getProperty("server.port"));

    context.publishEvent(new UserRegisteredEvent(context));
  }
}
